//////////////////////////////////////////////////////////////////////
// MsgRouter.cpp
//
// SHEN Fangyang
// me@shenfy.com
//
// Copyright (C) SHEN Fangyang, 2011, All rights reserved.
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//  Brief Description
//
//	Message struct and 
//	message router class for dispatching game messages.
//
//////////////////////////////////////////////////////////////////////
#include "grflib_stdafx.h"
#include "../include/MsgRouter.h"
#include "../include/StatedObj.h"
#include "../include/D3D10Engine.h"

namespace grflib { namespace engine { namespace AI {

CMsg::CMsg()
	: m_deliveryTime(0)
{}

CMsg::~CMsg()
{}

CMsg &CMsg::operator=(const CMsg &msg)
{
	if (&msg != this)
	{
		m_id = msg.m_id;
		m_receiverId = msg.m_receiverId;
		m_deliveryTime = msg.m_deliveryTime;
		m_package = msg.m_package;
	}
	return (*this);
}

CMsgRouter::CMsgRouter()
{
	InitializeCriticalSection(&m_cs);
	m_timer.Start();
}

CMsgRouter::~CMsgRouter()
{
	EnterCriticalSection(&m_cs);
	m_msgQueue.clear();
	LeaveCriticalSection(&m_cs);
	DeleteCriticalSection(&m_cs);
}

CMsgRouter &CMsgRouter::Instance()
{
	static CMsgRouter msgRouter;
	return msgRouter;
}

void CMsgRouter::SendMsg(const char *receiverId, const char *msgId, boost::shared_array<char> &pPackage, double delayInMS)
{
	boost::shared_ptr<CMsg> pMsg(new CMsg);
	pMsg->m_id = msgId;
	pMsg->m_receiverId = receiverId;
	pMsg->m_package = pPackage;
	pMsg->m_deliveryTime = m_timer.Snapshot() + delayInMS;
	EnterCriticalSection(&m_cs);
	m_msgQueue.push_back(pMsg);
	LeaveCriticalSection(&m_cs);	
}

double CMsgRouter::GetTime()
{
	return m_timer.Snapshot();
}

void CMsgRouter::Dispatch()
{
	using namespace grflib::engine::core;

    boost::shared_ptr<CMsg> pMsg;
	boost::shared_ptr<CStatedObj> pStatedObj;


	msg_queue_type::iterator iter = m_msgQueue.begin();
	while (true)
	{
		EnterCriticalSection(&m_cs);
		if (m_msgQueue.end() == iter) //no more items
		{
			LeaveCriticalSection(&m_cs);
			break; //end loop
		}

		if ((*iter)->m_deliveryTime > m_timer.Snapshot()) //not time yet
		{
			++iter;
			LeaveCriticalSection(&m_cs);
			continue; //skip
		}

		//we found a valid item, copy it then remove from list
		pMsg = *iter;
		iter = m_msgQueue.erase(iter);
		LeaveCriticalSection(&m_cs);
		
		//find target object, dispatch only if exists and is stated
		if (pStatedObj = _AIMan.FindObj(pMsg->m_receiverId)) //id found
		{
            //dispatch msg
            pStatedObj->GetFSM().OnMsg(*pMsg);
		}
	} //end of while
	
}

}}} //namespaces